package 蚂蚁课堂;

import java.util.concurrent.Exchanger;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Exchanger: 线程可以在成对内配对和交换元素的同步点
 * 每个线程在输入exchange方法时提供一些对象，与合作者线程匹配，并在返回时接收其合作伙伴的对象。 交换器可以被视为一个的双向形式SynchronousQueue 。
 * Exchanger 是 JDK 1.5 开始提供的一个用于两个工作线程之间交换数据的封装工具类，简单说就是一个线程在完成一定的事务后想与另一个线程交换数据，则第一个先拿出数据的线程会一直等待第二个线程，直到第二个线程拿着数据到来时才能彼此交换对应数据。其定义为 Exchanger<V> 泛型类型
 *
 * Exchanger类提供了一个exchange()方法：当一个线程到达 exchange 调用点时，如果其他线程此前已经调用了此方法，
 * 则其他线程会被调度唤醒并与之进行对象交换，然后各自返回；
 * 如果其他线程还没到达交换点，则当前线程会被挂起，直至其他线程到达才会完成交换并正常返回，或者当前线程被中断或超时返回。
 * 若其中一个超时，或者代码在exchange()方法抛出异常，则另一个线程就会永远停留在exchange()方法上，直到它的搭档也执行exchange()方法为止
 * 在多线程的情况下有可能消息会错乱，比如t1线程的消息存在和自己t1成对，t2会和t2成对，因为Exchanger在多线程情况下就不是典型的生产者、消费者模式
 * 他只要2个线程共用Exchanger对象，不管你是哪个线程，它们之间都能达到通信
 */
public class ExchangerDemo {

    private static Exchanger<String> exchanger=new Exchanger();
    public static AtomicInteger atomicInteger=new AtomicInteger(1);

    public static void main(String[] args) throws InterruptedException {

        while (true){
            TimeUnit.SECONDS.sleep(1);
            if (atomicInteger.compareAndSet(1,2)){
                t1();
                System.out.println("当前原子数据："+atomicInteger.get());
            }
            if (atomicInteger.compareAndSet(2,1)){
                t2();
                System.out.println("当前原子数据："+atomicInteger.get());
            }
        }
    }

    public static void t1(){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            String msg = exchanger.exchange("我是线程1的消息");
                            System.out.println("线程1："+msg);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                },"t1").start();
            }



    public static void t2(){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            String msg = exchanger.exchange("我是线程2的消息");
                            System.out.println("线程2:"+msg);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                },"t2").start();
            }
}


